<!-- 倒计时按钮 -->
<!-- 倒计时按钮 -->
<template>
  <el-button :color="color" style="display: flex" :loading="data.loading" :disabled="disabled || data.loading || data.status === 1" @click="onClick">
    <span v-if="loadingText && data.loading" :style="newStyle">{{ loadingText }}</span>
    <span v-else :style="newStyle">{{ data.text }}</span>
  </el-button>
</template>

<script setup lang="ts">
  import type {} from 'vue';
  const props = defineProps({
    /** 倒计时总秒数 */
    seconds: { type: Number, default: 60 },
    /** 尚未开始时提示 */
    startText: { type: String, default: '获取验证码' },
    /** 倒计时结束时的提示 */
    endText: { type: String, default: '重新获取' },
    /** 倒计时前缀 */
    prefix: { type: String, default: '' },
    /** 是否缓存倒计时 （从新进来时继续倒计时） */
    cache: { type: Boolean, default: true },
    /** 当有缓存时需要用onlyKey来存储时间，主要用于本地存储的key */
    storageKey: { type: String, default: '' },
    /** 倒计时后缀 */
    suffix: { type: String, default: '秒后可获取' },
    /** 当在发送网络请求时的文字（loading为 true 时） */
    loadingText: { type: String, default: '正在获取' },
    /** 字体颜色 */
    color: { type: String, default: 'var(--el-color-primary)' },
    /** 字体大小 */
    fontSize: { type: String, default: 'var(--my-change-base12-2x-size)' },
    /** 是否禁用 */
    disabled: { type: Boolean, default: false },
  });
  const emit = defineEmits<{
    (e: 'click'): void;
    (e: 'start'): void;
    (e: 'countDownChange', m: number): void;
    (e: 'change', state: 0 | 1 | 2): void;
    (e: 'end'): void;
  }>();
  const newStorageKey = computed(() => `mxp-count-down-button_${String(props.storageKey)}`);
  const newStyle = computed(() => {
    return { color: props.color, fontSize: props.fontSize, lineHeight: props.fontSize };
  });

  const data = shallowReactive({
    /** 是否正在发送网络请求 */
    loading: false,
    /** 剩余时间 */
    countDown: props.seconds,
    /** Timeout */
    timer: null as NodeJS.Timeout | null,
    /** 倒计时状态 0未倒计时，1正在倒计时，2倒计时完成 */
    status: 0 as 0 | 1 | 2,
    /** 显示的文本 */
    text: props.startText,
  });

  watch(
    () => data.status,
    (val) => {
      emit('change', val);
    },
    { immediate: true }
  );

  onMounted(() => {
    checkcache();
  });

  onUnmounted(() => {
    setTimeToStorage();
    data.timer && clearTimeout(data.timer);
    data.timer = null;
  });
  /** 检查 */
  function checkcache() {
    const lastTimestamp = Number(localStorage.getItem(newStorageKey.value));
    const nowTimestamp = Math.floor(Number(new Date()) / 1000);
    if (props.cache && !isNaN(lastTimestamp) && lastTimestamp && lastTimestamp > nowTimestamp) {
      data.countDown = lastTimestamp - nowTimestamp;
      localStorage.removeItem(newStorageKey.value);
      start();
    }
  }

  /** 开始倒计时 */
  function start() {
    clearIntervalFun();
    emit('start');
    data.status = 1;
    emit('countDownChange', data.countDown);
    data.text = props.prefix + data.countDown + props.suffix;
    data.timer = setInterval(() => {
      if (--data.countDown) {
        emit('countDownChange', data.countDown);
        data.text = props.prefix + data.countDown + props.suffix;
      } else {
        clearIntervalFun();
        localStorage.removeItem(newStorageKey.value);
        data.countDown = props.seconds;
        data.text = props.endText;
        emit('end');
        data.status = 2;
      }
    }, 1000);
    setTimeToStorage();
  }

  /** 重置，可以让用户再次获取验证码 */
  function reset() {
    data.loading = false;
    data.text = props.startText;
    clearIntervalFun();
    data.status = 0;
    data.countDown = props.seconds;
  }

  /** 保存时间戳，为了防止倒计时尚未结束，H5刷新或者各端的右上角返回上一页再进来 */
  function setTimeToStorage() {
    if (!props.cache || !data.timer) {
      return;
    }
    // 记录当前的时间戳，为了下次进入页面，如果还在倒计时内的话，继续倒计时
    // 倒计时尚未结束，结果大于0；倒计时已经开始，就会小于初始值，如果等于初始值，说明没有开始倒计时，无需处理
    if (data.countDown > 0 && data.countDown <= props.seconds) {
      // 获取当前时间戳(+ new Date()为特殊写法)，除以1000变成秒，再去除小数部分
      const nowTimestamp = Math.floor(Number(new Date()) / 1000);
      // 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数
      localStorage.setItem(newStorageKey.value, String(nowTimestamp + Number(data.countDown)));
    }
  }

  /** 清除计时器 */
  function clearIntervalFun() {
    if (data.timer) {
      clearInterval(data.timer);
      data.timer = null;
    }
  }

  /** 点击 */
  function onClick() {
    if (!props.disabled && data.status !== 1 && !data.loading) {
      emit('click');
    }
  }

  defineExpose({
    /** 开始倒计时 */
    start,
    /** 重置倒计时 */
    reset,
    /** 设置状态 */
    setLoadState(state: boolean) {
      data.loading = state;
    },
  });
</script>
